package com.fau.wmbj.server.storage;


import com.fau.wmbj.server.redis.utils.RedisUtils;
import com.fau.wmbj.server.utils.StringUtils;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.concurrent.TimeUnit;

/**
 * minio存储
 *
 * @author jiawei
 * @version 1.0
 * @datetime 2020/8/16 16:14
 */
@Slf4j
@Component("minioStorage")
public class MinioStorage extends Storage{


    @Override
    public String getName() {
        return "Minio存储";
    }


    @Override
    public String upload(String path, File file, String contentType, boolean open) {
        MinioClient minioClient = getMinioClient();
        String bucketName = getAttribute("bucketName");
        if (open) {
            bucketName = bucketName + "-open";
        }
        FileInputStream inputStream = null;
        try {
            if (minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                inputStream = new FileInputStream(file);
                PutObjectArgs build = PutObjectArgs.builder().bucket(bucketName).object(path).stream(inputStream, file.length(), -1).contentType(contentType).build();
                minioClient.putObject(build);
            }
        } catch (MinioException e) {
            log.error("minio文件上传失败", e);
        } catch (IOException | InvalidKeyException | NoSuchAlgorithmException e) {
            log.error("文件上传失败", e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("文件上传失败", e);
                }
            }

        }
        return path;
    }

    /**
     * 文件上传
     *
     * @param path          上传路径
     * @param multipartFile 上传文件
     * @return String 文件路径
     */
    @Override
    public String upload(String path, MultipartFile multipartFile, boolean open) {
        MinioClient minioClient = getMinioClient();
        String bucketName = getAttribute("bucketName");
        if (open) {
            bucketName = bucketName + "-open";
        }
        String extension = FilenameUtils.getExtension(multipartFile.getOriginalFilename());
        InputStream inputStream = null;
        try {
            if (minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                //logger.warn("minio开始：{}", simpleDateFormat.format(new Date()));
                inputStream = multipartFile.getInputStream();
                PutObjectArgs build = PutObjectArgs.builder().bucket(bucketName).object(path).stream(inputStream, multipartFile.getSize(), -1).build();
                minioClient.putObject(build);
                //logger.warn("minio完毕：{}", simpleDateFormat.format(new Date()));
                return path;
            }
        } catch (MinioException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    private MinioClient getMinioClient() {
        String endpoint = getAttribute("endpoint");
        String accessKey = getAttribute("accessKey");
        String secretKey = getAttribute("secretKey");
        MinioClient minioClient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
        return minioClient;
    }

    @Override
    public void delete(StorageDirectory fileDetail, boolean isPreview) {
        try {
            MinioClient minioClient = getMinioClient();
            String groupId = fileDetail.getGroupId();
            String url = isPreview ? fileDetail.getPreview() : fileDetail.getUrl();
            if (groupId == null) {
                groupId = getAttribute("bucketName");
            }
            if (StringUtils.isNotBlank(url) && minioClient.bucketExists(BucketExistsArgs.builder().bucket(groupId).build())) {
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(groupId).object(url).build());
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件删除
     *
     * @param url
     * @param groupId
     */
    @Override
    public void delete(String url, String groupId) {
        try {
            MinioClient minioClient = getMinioClient();
            if (groupId == null) {
                groupId = getAttribute("bucketName");
            }
            if (StringUtils.isNotBlank(url) && minioClient.bucketExists(BucketExistsArgs.builder().bucket(groupId).build())) {
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(groupId).object(url).build());
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getUrl(StorageDirectory fileDetail, boolean isPreview, int timeOut) {
        String fileName = isPreview ? fileDetail.getPreview() : fileDetail.getUrl();
        String groupId = fileDetail.getGroupId();
        String URL_PREFIX = isPreview ? "FILE_URL_PRE:" : "FILE_URL:";
        if (timeOut == 0) {
            String urlPrefix = getAttribute("urlPrefix") + "/" + groupId + "/" + fileDetail.getUrl();
            return urlPrefix;
        }
        if (groupId != null) {
            try {
                String endpoint = getAttribute("urlPrefix");
                String accessKey = getAttribute("accessKey");
                String secretKey = getAttribute("secretKey");
                MinioClient minioClient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
                String string = RedisUtils.getCacheObject(URL_PREFIX + fileDetail.getId()).toString();
                if (StringUtils.isNotBlank(string)) {
                    return string;
                } else {
                    String url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET)
                            .bucket(groupId)
                            .object(fileName)
                            .expiry(timeOut, TimeUnit.SECONDS)
                            .build());
                    RedisUtils.setCacheObject(URL_PREFIX + fileDetail.getId(), url, Duration.ofMillis(timeOut * 1000L));
                    return url;
                }
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (InsufficientDataException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (ErrorResponseException e) {
                e.printStackTrace();
            } catch (InternalException e) {
                e.printStackTrace();
            } catch (InvalidResponseException e) {
                e.printStackTrace();
            } catch (XmlParserException e) {
                e.printStackTrace();
            } catch (ServerException e) {
                e.printStackTrace();
            }
        }
        return "";
    }

    /**
     * 获取服务端存储路径
     *
     * @param diskPath 上传路径
     * @return 访问URL
     */
    @Override
    public String getStoragePath(String diskPath) {

        return diskPath;
    }

    /**
     * 下载文件
     *
     * @param fileDetail 文件详情
     * @author jiawei
     */
    @Override
    public InputStream download(StorageDirectory fileDetail, boolean isPreview) {
        String url = isPreview ? fileDetail.getPreview() : fileDetail.getUrl();
        String groupId = fileDetail.getGroupId();
        try {
            String endpoint = getAttribute("urlPrefix");
            String accessKey = getAttribute("accessKey");
            String secretKey = getAttribute("secretKey");
            MinioClient minioClient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
            if (StringUtils.isNotBlank(url) && groupId != null && minioClient.bucketExists(BucketExistsArgs.builder().bucket(groupId).build())) {
                GetObjectArgs build = GetObjectArgs.builder()
                        .bucket(groupId)
                        .object(url)
                        .build();
                InputStream stream = minioClient.getObject(build);
//                ByteArrayOutputStream output = new ByteArrayOutputStream();
//                byte[] buffer = new byte[1024 * 4];
//                int n = 0;
//                while (-1 != (n = stream.read(buffer))) {
//                    output.write(buffer, 0, n);
//                }
//                byte[] bytes = output.toByteArray();
//                stream.close();
//                output.close();
                return stream;
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        }
        return null;
    }
}
